package com.easyadmin.common.configure;

import java.io.Serializable;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;

import lombok.extern.slf4j.Slf4j;

/**
 * Redis Template 配置文件
 * <p>
 * @serial 2.0.0
 * @Author 程序员Mars
 */
@Slf4j
@Configuration
@EnableCaching // 添加支持缓存注解
public class RedisConfig {

	// 缓存生存时间
	@Value("${spring.redis.timeout:3600}")
	private long timeout;
	
    @Bean
    public RedisTemplate<String, Serializable> redisTemplate(LettuceConnectionFactory connectionFactory) {
        RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericFastJsonRedisSerializer());
        redisTemplate.setConnectionFactory(connectionFactory);
        return redisTemplate;
    }
    
    /**
	 * SpringCache 缓存配置
     * @author deer
     * @date 2024年1月22日
     * @param connectionFactory
     * @return
     */
	@Bean
	public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
		// redis缓存配置
		RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
				.entryTtl(Duration.ofMinutes(timeout))
				.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
				.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericFastJsonRedisSerializer()))
				.disableCachingNullValues();
		// 缓存配置map
		Map<String, RedisCacheConfiguration> cacheConfigurationMap = new HashMap<>();
		// 根据redis缓存配置和redis连接工厂生成redis缓存管理器
		RedisCacheManager redisCacheManager = RedisCacheManager.builder(connectionFactory).cacheDefaults(config)
				.transactionAware().withInitialCacheConfigurations(cacheConfigurationMap).build();
		return redisCacheManager;
	}
	
	/**
	 * 缓存异常处理
	 * 用于当redis连接不上时被缓存注解标注的方法绕过Redis直连数据库
	 * @author deer
	 * @date 2024年1月22日
	 * @return
	 */
	@Bean
	public CacheErrorHandler errorHandler() {
		CacheErrorHandler cacheErrorHandler = new CacheErrorHandler() {
			
			@Override
			public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {
				log.error("redis异常：key=[{}]", key, exception);
			}

			@Override
			public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {
				log.error("redis异常：key=[{}]", key, exception);
			}

			@Override
			public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {
				log.error("redis异常：key=[{}]", key, exception);
			}

			@Override
			public void handleCacheClearError(RuntimeException exception, Cache cache) {
				log.error("redis异常：", exception);
			}
		};
		
		return cacheErrorHandler;
	}

}
